package com.pointcircle.estate.server.admin.config;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.Filter;

import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.pointcircle.core.web.auth.JwtFilter;
import com.pointcircle.core.web.auth.JwtRealm;

@Configuration
public class ShiroConfig {
	
	@Value("${server.context-path}")
	private String contextPath;

	@Bean
	public FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean() {
	    FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean = 
	    	new FilterRegistrationBean<DelegatingFilterProxy>();
	    DelegatingFilterProxy proxy = new DelegatingFilterProxy();
	    proxy.setTargetFilterLifecycle(true);
	    proxy.setTargetBeanName("shiroFilter");
	    filterRegistrationBean.setFilter(proxy);
	    return filterRegistrationBean;
	}
	
	@Bean("shiroFilter")
	@Autowired
	public ShiroFilterFactoryBean shiroFilterFactoryBean(
			org.apache.shiro.mgt.SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		filterChainDefinitionMap.put("/auth/**", "anon");
		filterChainDefinitionMap.put("/**", "jwt");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		Map<String, Filter> mapFilters = new HashMap<String, Filter>();
		mapFilters.put("jwt", new JwtFilter());
		shiroFilterFactoryBean.setFilters(mapFilters);
		return shiroFilterFactoryBean;
	}
	
	@Bean
	@Autowired
	public SessionDAO sessionDAO() {
		EnterpriseCacheSessionDAO sessionDAO = new EnterpriseCacheSessionDAO();
		return sessionDAO;
	}
	
	@Bean
	@Autowired
	public SessionManager sessionManager(SessionDAO sessionDAO) {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setSessionDAO(sessionDAO);
		sessionManager.setSessionIdCookieEnabled(true);
		SimpleCookie cookie = new SimpleCookie();
		cookie.setName("POINT-CIRCLE-SESSION");
		cookie.setPath("/");
		sessionManager.setSessionIdCookie(cookie);
		return sessionManager;
	}
	
	@Bean
	@Autowired
	public org.apache.shiro.mgt.SecurityManager securityManager(
		SessionManager sessionManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		List<Realm> realms = new LinkedList<Realm>();
		JwtRealm jwtRealm = new JwtRealm();
		realms.add(jwtRealm);
		securityManager.setRealms(realms);
		securityManager.setSessionManager(sessionManager);
		return securityManager;
	}
	
	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		LifecycleBeanPostProcessor lifecycleBeanPostProcessor = 
			new LifecycleBeanPostProcessor();
		return lifecycleBeanPostProcessor;
	}
	
	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =
			new DefaultAdvisorAutoProxyCreator();
		defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
		return defaultAdvisorAutoProxyCreator;
	}
	
	@Bean
	@Autowired
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
		org.apache.shiro.mgt.SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
			new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
	
	@Bean
	public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
	    SimpleMappingExceptionResolver simpleMappingExceptionResolver
	    	= new SimpleMappingExceptionResolver();
	    Properties properties=new Properties();
	    properties.setProperty("org.apache.shiro.authz.AuthorizationException", "/authorException");
	    properties.setProperty("org.apache.shiro.authz.AuthenticationException", "/authenException");
	    simpleMappingExceptionResolver.setExceptionMappings(properties);
	    return simpleMappingExceptionResolver;
	}
}
